package jmcnet.libcommun.fop;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.avalon.framework.logger.ConsoleLogger;
import org.apache.fop.apps.Driver;
import org.apache.fop.messaging.MessageHandler;
import org.apache.log4j.Logger;
import org.xml.sax.InputSource;

/**
 * Cette classe permet le formattage d'un document Xml en document Pdf
 * @author Jean-Marc
 *
 */

public class FopFormatter {
	private static Logger log = Logger.getLogger(FopFormatter.class);
	private File xmlfile = null;
	private File xsltfile = null;
	private File pdffile = null;
	private File fofile=null;
	
	public FopFormatter(String inXmlFile, String inXsltFile, String outFoFile, String outPdfFile)
		throws FopFormatterException
	{
		log.info("Appel FopFormatter:CTOR inXmlFile="+inXmlFile+" inXsltFile="+inXsltFile+" outFoFile="+outFoFile+" outResFile="+outPdfFile);
        
		if (log.isDebugEnabled()) log.debug("Preparing...");

		// Setup input and output files            
		xmlfile = new File(inXmlFile);
		if (! xmlfile.canRead()) {
			FopFormatterException ffe = new FopFormatterException("Impossible de lire le fichier "+inXmlFile);
			log.error(ffe);
			throw ffe;
		}
		xsltfile = new File(inXsltFile);
		if (! xsltfile.canRead()) {
			FopFormatterException ffe = new FopFormatterException("Impossible de lire le fichier "+inXsltFile);
			log.error(ffe);
			throw ffe;
		}

		fofile= new File(outFoFile);
		pdffile = new File(outPdfFile);
		
		log.info("Fin FopFormatter:CTOR OK");
	}

	public void transformeXML2PDF() throws FopFormatterException {
		if (log.isDebugEnabled()) log.debug("Transforming to PDF ...");
		
		transformeXML2FO();

		OutputStream out=null;
		InputStream in=null;
		
		// Construct driver
        Driver driver = new Driver();
		if (log.isDebugEnabled()) log.debug("Apres new Driver");

        
        //Setup logger
        org.apache.avalon.framework.logger.Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG);
        driver.setLogger(logger);
        MessageHandler.setScreenLogger(logger);
		if (log.isDebugEnabled()) log.debug("Apres logger");


        //Setup Renderer (output format)        
        driver.setRenderer(Driver.RENDER_PDF);
        
		if (log.isDebugEnabled()) log.debug("Apres setRenderer");

        
		try {

			// Setup output
			out = new java.io.BufferedOutputStream(new java.io.FileOutputStream(pdffile));
			
			driver.setOutputStream(out);

			// Setup input
			in = new java.io.FileInputStream(fofile);
			driver.setInputSource(new InputSource(in));

			//Process FO
			driver.run();
		} catch (FileNotFoundException fne) {
			log.error("Impossible de trouver un fichier",fne);
			throw new FopFormatterException(fne);
		} catch (Exception e) {
			log.error("Impossible de transformer",e);
			throw new FopFormatterException(e);
		}
		finally {
			try {
				if (in != null) in.close();
				if (out != null) out.close();
			} catch (Exception e) { };
		}
	}
	
	public void transformeXML2FO() throws FopFormatterException {
		if (log.isDebugEnabled()) log.debug("Transforming to FO ...");

		OutputStream out=null;
		try {
			// Setup output
	        out = new java.io.FileOutputStream(fofile);
            
            //Setup XSLT
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(new StreamSource(xsltfile));
        
            //Setup input for XSLT transformation
            Source src = new StreamSource(xmlfile);
        
            //Resulting SAX events (the generated FO) must be piped through to FOP
            Result res = new StreamResult(out);

            //Start XSLT transformation and FOP processing
            transformer.transform(src, res);
        } catch (FileNotFoundException fne) {
			log.error("Impossible de trouver un fichier",fne);
			throw new FopFormatterException(fne);
		} catch (TransformerConfigurationException tce) {
			log.error("Impossible de transformer due a une mauvaise configuration",tce);
			throw new FopFormatterException(tce);
		} catch (TransformerException te) {
			log.error("Impossible de transformer",te);
			throw new FopFormatterException(te);
		} catch (Exception e) {
			log.error("Impossible de transformer",e);
			throw new FopFormatterException(e);
		}
		finally {
			try {
				if (out != null) out.close();
			} catch (Exception e) { };
		}
	}
	
	public static String remplacerCR(String src) {
		return src.replaceAll("\n", "&#x2028;");
	}
}
